package com.concurrence;

import com.Example.Model.Cert.CertInfo;
import com.Example.cert.GenerateX509V3;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.client.RepChainJksClient;
import com.google.protobuf.Timestamp;
import com.google.protobuf.util.JsonFormat;
import com.protos.Peer;
import com.utils.PemUtil;
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;

/**
 * 注册证书
 */
public class SignUpCert extends Thread {

    // 账户管理合约ID
    private Peer.ChaincodeId contractCertId = Peer.ChaincodeId.newBuilder().setChaincodeName("ContractCert").setVersion(1).build();
    // 账户列表
    ArrayList creditCodeList = new ArrayList();
    // 各个管理员节点的账户地址
    private String[] node_addr = {"121000005l35120456", "12110107bi45jh675g", "122000002n00123567", "921000005k36123789", "921000006e0012v696"};
    // 普通用户的地址
    ArrayList<String> creditCodes = new ArrayList<>();
    // 普通账户的私钥地址
    ArrayList<PrivateKey> privateKeys = new ArrayList<>();
    // 私钥与账户的对应MAP
    HashMap<String, PrivateKey> map = new HashMap<>();

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    public SignUpCert() {
    }

    /**
     * 初始化账户地址表
     *
     * @param creditCodes
     */
    public SignUpCert(ArrayList creditCodes) {
        this.creditCodes = creditCodes;
    }

    @Override
    public void run() {
        Random random = new Random();
        // 循环向列表中的账户注册证书
        for (String creditCode : creditCodes) {
            try {
                String certPem = createPriKeyAndCert(creditCode);
                signUpCert(random.nextInt(4), creditCode, certPem, "certName_3");
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    /**
     * 注册证书
     *
     * @param i
     * @param creditCode
     * @param certPem
     * @param certName
     * @throws Exception
     */
    void signUpCert(int i, String creditCode, String certPem, String certName) throws Exception {

        RepChainJksClient adminClient = new RepChainJksClient(
                "localhost:8081",
                "jks/" + node_addr[i] + ".node" + (i + 1) + ".jks", "123",
                node_addr[i] + ".node" + (i + 1));

        // 管理员证书ID
        Peer.CertId adminCertId = Peer.CertId.newBuilder().setCreditCode(node_addr[i]).setCertName("node" + (i + 1)).build();

        // 注册时间
        long regMillis = System.currentTimeMillis() + 8 * 3600 * 1000;
        // 注销时间
        long unRegMillis = System.currentTimeMillis() + 2 * 8 * 3600 * 1000;
        Timestamp regTime = Timestamp.newBuilder().setSeconds(regMillis / 1000).setNanos((int) (regMillis % 1000) * 1000000).build();
        Timestamp unRegTime = Timestamp.newBuilder().setSeconds(unRegMillis / 1000).setNanos((int) (unRegMillis % 1000) * 1000000).build();
        // 也可以自己构造一个javaBean，然后使用Json序列化
        Peer.Certificate certificate = Peer.Certificate.newBuilder()
                .setCertificate(certPem)
                .setAlgType("SHA1withECDSA")
                .setCertValid(true)
                .setRegTime(regTime)
                .setUnregTime(unRegTime)
                .build();
        // 也可以自己构造一个javaBean，然后使用Json序列化
        CertInfo certInfo = new CertInfo(creditCode, certName, JSON.parse(JsonFormat.printer().print(certificate)));
        Peer.Transaction signUpCer = adminClient.createTransactionForInvoke(adminCertId, contractCertId, "SignUpCert", JSON.toJSONString(certInfo));
        String signUpCerStr = Hex.encodeHexString(signUpCer.toByteArray());
        JSONObject jsonObject = adminClient.postTranByString(JSON.toJSONString(signUpCerStr));
        System.out.println(Thread.currentThread().getName() + ": signUpCert: " + jsonObject);
    }

    // 构建证书,并返回字符串
    String createPriKeyAndCert(String creditCode) throws Exception {
        // 构建密钥对
        KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC", "BC");
//        kpGen.initialize(new ECNamedCurveGenParameterSpec("secp256k1"));
        kpGen.initialize(ECNamedCurveTable.getParameterSpec("secp256k1"));
        KeyPair keyPair = kpGen.generateKeyPair();
        PrivateKey privateKey = keyPair.getPrivate();
        privateKeys.add(privateKey);
        map.put(creditCode, privateKey);
        // 构建自签名证书
        X509Certificate certificate = GenerateX509V3.makeV3Certificate("SHA256WITHECDSA", keyPair);
        return PemUtil.toPemString(certificate);
    }

    public ArrayList<PrivateKey> getPrivateKeys() {
        return privateKeys;
    }

    public HashMap<String, PrivateKey> getMap() {
        return map;
    }
}
